package com.payment.controller.payment;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.payment.entity.pay.wxpay.requset.*;
import com.payment.entity.pay.wxpay.response.*;
import com.payment.service.SequenceService;
import com.payment.utils.MD5;
import com.payment.utils.UtilsInterfacesPackage;
import com.payment.utils.WxPayUtil;
import com.payment.utils.payment.WxPayConstants;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/wxWeb")
@Api(description = "微信H5支付")
/**
 * 1，使用领科的微信收款账号收款，微信H5支付接口：
 *
 * 2，适用于老的客户：第一版的领科商城；
 *
 * 3，更新的数据表为：user_order_payment_manager_t；
 *
 *  4，更新的数据库为：links
 *
 * @author lm
 * @date 2019/11/06
 */
public class WeiXinPayH5Controller {

    private static Logger logger = Logger.getLogger(WeiXinPayH5Controller.class);
    @Autowired
    private SequenceService sequenceService;

    /***微信支付付款接口
     *
     * @param requestWeiXinPay
     * @param request
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/wxPay", produces = "application/json;charset=utf-8", method = RequestMethod.POST)
    @CrossOrigin
    @ResponseBody
    @ApiOperation(value = "微信支付下单", response = ResponseWeiXinPay.class)
    public String wxPayH5(@ApiParam @RequestBody RequestWeiXinPay requestWeiXinPay, HttpServletRequest request) throws Exception {
        // 1，生成流水号
        String connSeqNo = sequenceService.getPackageTaskNo();
        // 2,生成当前时间戳
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String curtime = df.format(new Date());
        //3，定义回报报文
        String jsonString;
        UtilsInterfacesPackage utils = new UtilsInterfacesPackage();
        String requestStr = JSON.toJSONString(requestWeiXinPay);
        if (requestStr == null) {
            logger.info("请求报文不合法:requestStr为空");
            jsonString = utils.dataWeiKong(connSeqNo, curtime);
            return jsonString;
        } else {
            logger.info("前端请求报文是：" + requestStr);
            RequestWeiXinPay requestPackage = JSONArray.parseObject(requestStr, RequestWeiXinPay.class);
            String requestSign = requestPackage.getSign();
            if (requestSign == null) {
                logger.info("请求报文不合法:sign为空");
                jsonString = utils.dataWeiKong(connSeqNo, curtime);
                return jsonString;
            } else {
                logger.info("请求的签名是：" + requestSign);
                RequestWeiXinPayData requestData = requestPackage.getData();
                if (requestData == null) {
                    logger.info("请求报文不合法:data为空");
                    jsonString = utils.dataWeiKong(connSeqNo, curtime);
                    return jsonString;
                } else {
                    String partnerCode = requestData.getPartnerCode();
                    String ConnSeqNo = requestData.getConnSeqNo();
                    String tradeTime = requestData.getTradeTime();
                    String token = requestData.getToken();
                    String tradeType = requestData.getTradeType();
                    String lang = requestData.getLang();

                    if (requestData.getTradeData() == null || StringUtils.isBlank(partnerCode) || StringUtils.isBlank(tradeTime) || StringUtils.isBlank(token) || StringUtils.isBlank(tradeType) || StringUtils.isBlank(lang)) {
                        logger.info("请求报文不合法:data参数不合法");
                        jsonString = utils.dataWeiKong(connSeqNo, curtime);
                        return jsonString;
                    } else {
                        RequestWeiXinPayTradeData requestTradeData = requestData.getTradeData();
                        String orderId = requestTradeData.getOrderId();
                        String amount = requestTradeData.getAmount();
                        if (orderId == null || orderId == "" || amount == null || amount == "") {
                            System.out.println("请求报文不合法:orderId和amount不可以为空！");
                            jsonString = utils.dataWeiKong(connSeqNo, curtime);
                            return jsonString;
                        } else {
                            // 将请求体json转成String
                            String str = JSON.toJSONString(requestData);
                            // 将Str拿去计算签名
                            String sign = utils.calculateSignature(str);
                            logger.info("计算的签名是：" + sign);
                            if (!requestSign.equalsIgnoreCase(sign)) {
                                logger.info("签名验证失败！");
                                jsonString = utils.publicMessage(ConnSeqNo, partnerCode, tradeTime, token, tradeType);
                                return jsonString;
                            } else {
                                // 统一下单，返回xml，用return_code判断统一下单结果,获取prepay_id等预支付成功信息
                                // 获取ip地址:
                                String ipAddrStr = WxPayUtil.getIp2(request);
                                logger.info("新的获取的ip地址是：" + ipAddrStr);
                                // 将传过来的金额处理一下
                                boolean flag = WxPayUtil.isInteger(amount);
                                //商品描述
                                //String body = "领科-流量重值";
                                String body = "IotCardTrafficRecharge";
                                //场景信息
                                String scene_info = "{\"h5_info\":\"h5_info\" {\"type\":\"WAP\",\"wap_url\":\"http://wx.linksfield.net\",\"wap_name\":\"IotCardTrafficRecharge\"}}";
                                // 如果是整型
                                if (flag == true) {
                                    int Amount = Integer.valueOf(amount).intValue();
                                    int totel_fee = Amount * 100;
                                    String prePayInfoXml = WxPayUtil.UnifiedOrderH5(body, scene_info, orderId, totel_fee, ipAddrStr);
                                    logger.info("Controller中的prePayInfoXml：" + prePayInfoXml);
                                    // 生成包含prepay_id的map，map传入前端
                                    Map<String, Object> map = new HashMap<String, Object>();
                                    map = WxPayUtil.getPayH5Map(prePayInfoXml);
                                    logger.info("Controller中的map：" + map);

                                    String prepay_id = (String) map.get("prepay_id");
                                    request.setAttribute("prepay_id", prepay_id);
                                    String mweb_url = (String) map.get("mweb_url");
                                    request.setAttribute("mweb_url", mweb_url);
                                    //回报报文TradeData
                                    ResponseWeiXinPayTradeData responseTradeData = new ResponseWeiXinPayTradeData();
                                    responseTradeData.setPrepay_id(prepay_id);
                                    responseTradeData.setMweb_url(mweb_url);
                                    responseTradeData.setOrderId(orderId);
                                    //回报Data
                                    ResponseWeiXinPayData data = new ResponseWeiXinPayData();
                                    data.setConnSeqNo(ConnSeqNo);
                                    data.setPartnerCode(partnerCode);
                                    data.setToken(token);
                                    data.setTradeType(tradeType);
                                    data.setTradeTime(tradeTime);
                                    data.setTradeRstCode(1000);
                                    data.setTradeRstMessage("success");
                                    data.setTradeData(responseTradeData);

                                    ResponseWeiXinPay responseWeiXinPay = new ResponseWeiXinPay();
                                    responseWeiXinPay.setData(data);
                                    responseWeiXinPay.setSign(MD5.calcMD5(JSON.toJSONString(data)));
                                    // 返回给调用者的报文
                                    jsonString = JSON.toJSONString(responseWeiXinPay);
                                    logger.info("响应报文：" + jsonString);
                                    return jsonString;

                                } else {
                                    // DecimalFormat("#")表示float类型格式化时不要小数点了
                                    DecimalFormat decimalFormat = new DecimalFormat("#");
                                    float Amount = Float.parseFloat(amount);
                                    int totel_fee = Integer.parseInt(decimalFormat.format(Amount * 100));
                                    String prePayInfoXml = WxPayUtil.UnifiedOrderH5(body, scene_info, orderId, totel_fee, ipAddrStr);
                                    logger.info("Controller中的prePayInfoXml：" + prePayInfoXml);
                                    // 生成包含prepay_id的map，map传入前端
                                    Map<String, Object> map = new HashMap<String, Object>();
                                    map = WxPayUtil.getPayH5Map(prePayInfoXml);
                                    logger.info("Controller中的map：" + map);
                                    // 将订单号放入map，用以支付后处理
                                    String prepay_id = (String) map.get("prepay_id");
                                    request.setAttribute("prepay_id", prepay_id);
                                    String mweb_url = (String) map.get("mweb_url");
                                    request.setAttribute("mweb_url", mweb_url);
                                    //回报报文TradeData
                                    ResponseWeiXinPayTradeData responseTradeData = new ResponseWeiXinPayTradeData();
                                    responseTradeData.setPrepay_id(prepay_id);
                                    responseTradeData.setMweb_url(mweb_url);
                                    responseTradeData.setOrderId(orderId);
                                    //回报Data
                                    ResponseWeiXinPayData data = new ResponseWeiXinPayData();
                                    data.setConnSeqNo(ConnSeqNo);
                                    data.setPartnerCode(partnerCode);
                                    data.setToken(token);
                                    data.setTradeType(tradeType);
                                    data.setTradeTime(tradeTime);
                                    data.setTradeRstCode(1000);
                                    data.setTradeRstMessage("success");
                                    data.setTradeData(responseTradeData);

                                    ResponseWeiXinPay responseWeiXinPay = new ResponseWeiXinPay();
                                    responseWeiXinPay.setData(data);
                                    responseWeiXinPay.setSign(MD5.calcMD5(JSON.toJSONString(data)));
                                    // 返回给调用者的报文
                                    jsonString = JSON.toJSONString(responseWeiXinPay);
                                    logger.info("响应报文：" + jsonString);
                                    return jsonString;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /****
     * 1,微信订单状态查询接口：直接去微信平台查询的
     *
     * @param requestWeiXinQueryOrder
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/wxQueryOrder", produces = "application/json;charset=utf-8", method = RequestMethod.POST)
    @CrossOrigin
    @ResponseBody
    @ApiOperation(value = "微信订单状态查询", response = ResponseWeiXinQueryOrder.class)
    public String orderQuery(@ApiParam @RequestBody RequestWeiXinQueryOrder requestWeiXinQueryOrder) throws Exception {
        // 1，生成流水号
        String connSeqNo = sequenceService.getPackageTaskNo();
        // 2,生成当前时间戳
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String curtime = df.format(new Date());
        //3，定义回报报文
        String jsonString = "";
        UtilsInterfacesPackage utils = new UtilsInterfacesPackage();
        String requestStr = JSON.toJSONString(requestWeiXinQueryOrder);
        if (requestStr == null) {
            logger.info("请求报文不合法:requestStr为空");
            jsonString = utils.dataWeiKong(connSeqNo, curtime);
            return jsonString;
        } else {
            logger.info("前端请求报文是：" + requestStr);
            RequestWeiXinQueryOrder requestPackage = JSONArray.parseObject(requestStr, RequestWeiXinQueryOrder.class);
            String requestSign = requestPackage.getSign();
            if (requestSign == null) {
                logger.info("请求报文不合法:sign为空");
                jsonString = utils.dataWeiKong(connSeqNo, curtime);
                return jsonString;
            } else {
                logger.info("请求的签名是：" + requestSign);
                RequestWeiXinQueryOrderData requestData = requestPackage.getData();
                if (requestData == null) {
                    logger.info("请求报文不合法:data为空");
                    jsonString = utils.dataWeiKong(connSeqNo, curtime);
                    return jsonString;
                } else {
                    String partnerCode = requestData.getPartnerCode();
                    String ConnSeqNo = requestData.getConnSeqNo();
                    String tradeTime = requestData.getTradeTime();
                    String token = requestData.getToken();
                    String tradeType = requestData.getTradeType();
                    String lang = requestData.getLang();

                    if (StringUtils.isBlank(partnerCode) || StringUtils.isBlank(ConnSeqNo) || StringUtils.isBlank(tradeTime) || StringUtils.isBlank(token) ||
                            StringUtils.isBlank(tradeType) || requestData.getTradeData() == null) {
                        logger.info("请求报文不合法:data参数不合法");
                        jsonString = utils.dataWeiKong(connSeqNo, curtime);
                        return jsonString;
                    } else {
                        // 将请求体json转成String
                        String str = JSON.toJSONString(requestData);
                        // 将Str拿去计算签名
                        String signs = utils.calculateSignature(str);
                        logger.info("计算的签名是：" + signs);
                        if (!requestSign.equalsIgnoreCase(signs)) {
                            logger.info("签名验证失败！");
                            jsonString = utils.publicMessage(ConnSeqNo, partnerCode, tradeTime, token, tradeType);
                            return jsonString;
                        } else {
                            RequestWeiXinQueryOrderTradeData requestTradeData = requestData.getTradeData();

                            String out_trade_no = requestTradeData.getOrderId();
                            //这个值是前端不知道的
                            String transaction_id = "";
                            logger.info("取出的out_trade_no是：" + out_trade_no);
                            String prePayInfoXml = WxPayUtil.orderQuery(transaction_id, out_trade_no);
                            logger.info("Controller中的prePayInfoXml：" + prePayInfoXml);

                            String return_code = WxPayUtil.getXmlPara(prePayInfoXml, "return_code");
                            String return_msg = WxPayUtil.getXmlPara(prePayInfoXml, "return_msg");
                            String appid = WxPayUtil.getXmlPara(prePayInfoXml, "appid");
                            String mch_id = WxPayUtil.getXmlPara(prePayInfoXml, "mch_id");
                            String device_info = WxPayUtil.getXmlPara(prePayInfoXml, "device_info");
                            String nonce_str = WxPayUtil.getXmlPara(prePayInfoXml, "nonce_str");
                            String sign = WxPayUtil.getXmlPara(prePayInfoXml, "sign");
                            String result_code = WxPayUtil.getXmlPara(prePayInfoXml, "result_code");
                            String openid = WxPayUtil.getXmlPara(prePayInfoXml, "openid");
                            String is_subscribe = WxPayUtil.getXmlPara(prePayInfoXml, "is_subscribe");
                            String trade_type = WxPayUtil.getXmlPara(prePayInfoXml, "trade_type");
                            out_trade_no = WxPayUtil.getXmlPara(prePayInfoXml, "out_trade_no");
                            String bank_type = WxPayUtil.getXmlPara(prePayInfoXml, "bank_type");
                            String total_fee = WxPayUtil.getXmlPara(prePayInfoXml, "total_fee");
                            String fee_type = WxPayUtil.getXmlPara(prePayInfoXml, "fee_type");
                            transaction_id = WxPayUtil.getXmlPara(prePayInfoXml, "transaction_id");
                            String attach = WxPayUtil.getXmlPara(prePayInfoXml, "attach");
                            String time_end = WxPayUtil.getXmlPara(prePayInfoXml, "time_end");
                            String trade_state = WxPayUtil.getXmlPara(prePayInfoXml, "trade_state");
                            // 根据返回xml计算本地签名
                            String localSign =
                                    "appid=" + appid +
                                            "&attach=" + attach +
                                            "&bank_type=" + bank_type +
                                            "&device_info=" + device_info +
                                            "&fee_type=" + fee_type +
                                            "&is_subscribe=" + is_subscribe +
                                            "&mch_id=" + mch_id +
                                            "&nonce_str=" + nonce_str +
                                            "&openid=" + openid +
                                            "&out_trade_no=" + out_trade_no +
                                            "&result_code=" + result_code +
                                            "&return_code=" + return_code +
                                            "&return_msg=" + return_msg +
                                            "&time_end=" + time_end +
                                            "&total_fee=" + total_fee +
                                            "&trade_state=" + trade_state +
                                            "&trade_type=" + trade_type +
                                            "&transaction_id=" + transaction_id +
                                            "&key=" + WxPayConstants.KEY;// 注意这里的参数要根据ASCII码 排序
                            //将数据MD5加密
                            localSign = MD5.calcMD5(localSign).toUpperCase();
                            logger.info("查询接口本地签名是：" + localSign + ";查询微信支付签名是:" + sign);

                            //开始接口返回,将微信返回的结果直接返回
                            ResponseWeiXinQueryOrderTradeData responseTradeData = new ResponseWeiXinQueryOrderTradeData();
                            responseTradeData.setTradeState(trade_state);
                            responseTradeData.setOrderId(out_trade_no);

                            ResponseWeiXinQueryOrderData data = new ResponseWeiXinQueryOrderData();
                            data.setConnSeqNo(ConnSeqNo);
                            data.setPartnerCode(partnerCode);
                            data.setToken(token);
                            data.setTradeType(tradeType);
                            data.setTradeTime(tradeTime);
                            data.setTradeRstCode(1000);
                            data.setTradeRstMessage("success");
                            data.setTradeData(responseTradeData);

                            ResponseWeiXinQueryOrder responseOrder = new ResponseWeiXinQueryOrder();
                            responseOrder.setData(data);
                            responseOrder.setSign(MD5.calcMD5(JSON.toJSONString(data)));

                            // 返回给调用者的报文
                            jsonString = JSON.toJSONString(responseOrder);
                            logger.info("响应报文：" + jsonString);
                            return jsonString;

                        }
                    }
                }
            }
        }
    }
}

